package com.zdxlz.desensitize.core;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.zdxlz.desensitize.constant.ColumnType;
import com.zdxlz.desensitize.constant.DesensitizeType;
import com.zdxlz.desensitize.domain.DesensitizeRule;
import com.zdxlz.desensitize.domain.DesensitizeRuleDto;
import com.zdxlz.desensitize.domain.RuleTree;
import com.zdxlz.desensitize.util.DesensitizeUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 数据脱敏基础拦截器
 */
public class BaseDesensitizeAspect {
    private IDesensitizeService desensitizeService;

    private DesensitizeUtil desensitizeUtil;

    public void setDesensitizeService(IDesensitizeService desensitizeService) {
        this.desensitizeService = desensitizeService;
    }

    public void setDesensitizeUtil(DesensitizeUtil desensitizeUtil) {
        this.desensitizeUtil = desensitizeUtil;
    }

    /**
     * 简单模式脱敏处理
     */
    public Object sensitiveFormat(Object obj, HttpServletRequest request) {
        if (null == desensitizeService || null == desensitizeUtil) {
            return obj;
        }
        return sensitiveFormat(obj,desensitizeService.getRuleDtos(desensitizeService.getRoles(request),request.getRequestURI()));
    }

    /**
     * 复杂模式脱敏处理
     */
    public Object sensitiveFormat(Object obj, RequiredDesensitize anno, HttpServletRequest request) {
        if (null == desensitizeService || null == desensitizeUtil) {
            return obj;
        }
        return sensitiveFormat(obj, anno, desensitizeService.getRules(desensitizeService.getRoles(request)));
    }

    /**
     * 脱敏处理
     */
    public Object sensitiveFormat(Object obj,RequiredDesensitize anno, List<DesensitizeRule> rules) {
        if (null == rules || rules.isEmpty() || null == desensitizeUtil) {
            return obj;
        }
        List<DesensitizeRuleDto> dtos = buildDtos(anno, rules);
        return sensitiveFormat(obj, dtos);
    }

    /**
     * 脱敏处理
     */
    public Object sensitiveFormat(Object obj,List<DesensitizeRuleDto> dtos) {
        if (null == dtos || dtos.isEmpty() || null == desensitizeUtil) {
            return obj;
        }
        // 将规则转化为树状结构
        RuleTree ruleTree = buildTree(dtos);
        // 遍历树，进行脱敏
        return sensitiveFormat(obj, ruleTree);
    }

    /**
     * 脱敏处理
     */
    public Object sensitiveFormat(Object obj,RuleTree ruleTree) {
        if (null == ruleTree || null == desensitizeUtil) {
            return obj;
        }
        // 先序遍历规则树，返回结果
        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(obj));
        JSONObject newJson = preOrder(jsonObject, ruleTree);
        return JSON.parseObject(newJson.toJSONString(), obj.getClass());
    }

    /**
     * 构建dto列表
     */
    public List<DesensitizeRuleDto> buildDtos(RequiredDesensitize anno, List<DesensitizeRule> rules) {
        List<DesensitizeRuleDto> results = new ArrayList<>();
        for(DesensitizeRule rule: rules) {
            ColumnType column = rule.getColumn();
            switch (column){
                case PHONE:
                    addDtos(results, anno.phone(), rule.getType(), rule.getValue());
                    break;
                case IDCARD:
                    addDtos(results, anno.idCard(), rule.getType(), rule.getValue());
                    break;
                case EMAIL:
                    addDtos(results, anno.email(), rule.getType(), rule.getValue());
                    break;
                case OFFICEPASS:
                    addDtos(results, anno.officePass(), rule.getType(), rule.getValue());
                    break;
                case NAME:
                    addDtos(results, anno.name(), rule.getType(), rule.getValue());
                    break;
                case ADDRESS:
                    addDtos(results, anno.address(), rule.getType(), rule.getValue());
                    break;
                case OTHER:
                    addDtos(results, anno.other(), rule.getType(), rule.getValue());
                    break;
                default:
                    break;
            }
        }
        return results;
    }

    /**
     * 添加到dto列表中
     */
    public void addDtos(List<DesensitizeRuleDto> results, String[] strs, DesensitizeType type, Integer value) {
        if (strs.length == 0) {
            return;
        }
        // 空和不脱敏类型不脱敏
        if (null == type || type.equals(DesensitizeType.NOT)){
            return;
        }
        for (String str : strs) {
            DesensitizeRuleDto desensitizeRuleDto = new DesensitizeRuleDto();
            desensitizeRuleDto.setColumn(str);
            desensitizeRuleDto.setType(type);
            if (null != value) {
                desensitizeRuleDto.setValue(value);
            }
            results.add(desensitizeRuleDto);
        }
    }

    /**
     * 先序遍历规则树，返回结果
     */
    public JSONObject preOrder(JSONObject jsonObject, RuleTree ruleTree) {
        if (ruleTree == null) {
            return jsonObject;
        }
        if (!ruleTree.isLeaf()) {
            Map<String, RuleTree> children = ruleTree.getChildren();
            for (RuleTree child:children.values()) {
                if (child.isLeaf()) {
                    desensitize(jsonObject, child);
                }else {
                    String id = child.getId();
                    if(jsonObject.containsKey(id)){
                        Object o = jsonObject.get(id);
                        if (o instanceof List) {
                            List jsonList = (List) o;
                            List<JSONObject> arrayList = new ArrayList<>();
                            for (Object listChild: jsonList) {
                                JSONObject jsonObject1 = preOrder(JSON.parseObject(JSON.toJSONString(listChild)), child);
                                arrayList.add(jsonObject1);
                            }
                            jsonObject.put(id, arrayList);
                        }else {
                            JSONObject childJson = JSON.parseObject(JSON.toJSONString(o));
                            if (null != childJson) {
                                JSONObject jsonObject1 = preOrder(childJson, child);
                                jsonObject.put(id, jsonObject1);
                            }
                        }
                    }
                }
            }
        }
        return jsonObject;
    }

    /**
     * 脱敏处理
     */
    private void desensitize(JSONObject jsonObject, RuleTree node) {
        String id = node.getId();
        if (jsonObject.containsKey(id)) {
            String string = jsonObject.getString(id);
            String desensitized = desensitizeUtil.desensitized(string, node.getType(), node.getValue());
            jsonObject.put(id, desensitized);
        }
    }

    /**
     * 构建树
     */
    public static RuleTree buildTree(List<DesensitizeRuleDto> list){
        // 创建根节点
        RuleTree ruleTree = new RuleTree();
        // 根据column 进行分组
        for(DesensitizeRuleDto rule: list) {
            String column = rule.getColumn();
            String[] splits = column.split("\\.");
            recursionFnTree(ruleTree, splits, 0, splits.length-1, rule.getType(), rule.getValue());
        }
        // 返回根
        return ruleTree;
    }

    /**
     * 递归
     * @param splits 根节点到叶子节点
     * @param ruleTree 树
     */
    public static void recursionFnTree(RuleTree ruleTree, String[] splits, int idx, int len, DesensitizeType type, Integer value){
        if (idx < len) {
            String str = splits[idx];
            // 如果没有此孩子
            RuleTree ruleTree1;
            if(!ruleTree.hasChild(str)){
                ruleTree1 = new RuleTree();
                ruleTree1.setId(str);
                ruleTree.addChildren(ruleTree1);
            }else {
                ruleTree1 = ruleTree.getChild(str);
            }
            idx ++;
            recursionFnTree(ruleTree1, splits, idx, len, type, value);
        }else if(idx==len){
            String str = splits[idx];
            // 如果没有此孩子
            if(!ruleTree.hasChild(str)){
                RuleTree ruleTree1 = new RuleTree();
                ruleTree1.setId(str);
                ruleTree1.setType(type);
                if (null != value) {
                    ruleTree1.setValue(value);
                }
                ruleTree.addChildren(ruleTree1);
            }
        }
    }

    /**
     * 基本数据类型和String类型判断
     */
    public static boolean isPrimitive(Class<?> clz) {
        try {
            if (String.class.isAssignableFrom(clz) || clz.isPrimitive()) {
                return true;
            } else {
                return ((Class<?>) clz.getField("TYPE").get(null)).isPrimitive();
            }
        } catch (Exception e) {
            return false;
        }
    }
}

